using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace Zsa.Reflection.Discovery
{
    /// <summary>
    /// Search for types.
    /// </summary>
    public class TypeSearch : SearchBase
    {
        #region Fields
        /// <summary>
        /// The search criteria.
        /// </summary>
        private TypeSearchCriteria _SearchCriteria;
        #endregion Fields

        #region Constructor
        /// <summary>
        /// Initializes a new instance of the <see cref="TypeSearch"/> class.
        /// </summary>
        public TypeSearch()
            : this ( new TypeSearchCriteria() )
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TypeSearch"/> class.
        /// </summary>
        /// <param name="searchCriteria">The search criteria.</param>
        public TypeSearch(TypeSearchCriteria searchCriteria)
        {
            _SearchCriteria = searchCriteria;
        }
        #endregion Constructor

        #region Methods


        public IList<KeyValuePair<Type, IList<MemberInfo>>> FindMembers()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        /// <summary>
        /// Finds the attributes.
        /// </summary>
        /// <param name="assemblies">The assemblies.</param>
        /// <returns></returns>
        public IList<KeyValuePair<Type,IList<Attribute>>> FindAttributes(Assembly[] assemblies)
        {
            throw new Exception("The method or operation is not implemented.");
            //try
            //{
            //    IList<KeyValuePair<Type, IList<Attribute>>> _Types =
            //        new List<KeyValuePair<Type, IList<Attribute>>>(20);
            //    Assembly _Asm = includeUtilAsm ?
            //        typeof(TypeSearch).Assembly : null;
            //    for (int _AsmIndex = 0; _AsmIndex < assemblies.Length; _AsmIndex++)
            //    {
            //        if (includeUtilAsm && _Asm == assemblies[_AsmIndex])
            //        {
            //            continue;
            //        }
            //        Find(
            //            new TypeFoundHandler(
            //                delegate(Type type, object state)
            //                {
            //                    List<Type> _ListState = state as List<Type>;
            //                    _ListState.Add(type);
            //                    return true;
            //                }
            //            ),
            //            assemblies[_AsmIndex],
            //            _Types
            //        );
            //    }
            //    return _Types;
            //}
            //catch
            //{
            //    throw;
            //}
        }

        /// <summary>
        /// Finds the types.
        /// </summary>
        /// <returns></returns>
        public IList<Type> FindTypes()
        {
            return FindTypes(AppDomain.CurrentDomain.GetAssemblies(), false);
        }


        /// <summary>
        /// Finds the types.
        /// </summary>
        /// <param name="assemblies">The assemblies.</param>
        /// <returns></returns>
        public IList<Type> FindTypes(Assembly[] assemblies)
        {
            return FindTypes(assemblies, false);
        }

        /// <summary>
        /// Finds the types.
        /// </summary>
        /// <param name="assemblies">The assemblies.</param>
        /// <param name="includeAssembly">if set to <c>true</c> [include assembly].</param>
        /// <returns></returns>
        internal IList<Type> FindTypes(Assembly[] assemblies,
            bool includeAssembly)
        {
            return FindTypes(
                assemblies,
                delegate(Assembly asm)
                {
                    return asm == typeof(TypeSearch).Assembly;
                }
            );
        }

        /// <summary>
        /// Finds the types.
        /// </summary>
        /// <param name="assemblies">The assemblies.</param>
        /// <param name="includeUtilAsm">if set to <c>true</c> [include util asm].</param>
        /// <returns></returns>
        private IList<Type> FindTypes(Assembly[] assemblies, 
            Predicate<Assembly> assemblyFilters )
        {
            try
            {
                List<Type> _Types = new List<Type>(20);

                Predicate<Assembly>[] _Filters = (assemblyFilters == null ? 
                    new Predicate<Assembly>[0] :
                    Array.ConvertAll<Delegate,Predicate<Assembly>>(
                        assemblyFilters.GetInvocationList(),
                        delegate ( Delegate del )
                        {
                            return del as Predicate<Assembly>;
                        }
                ));
                bool _IsValid = true;

                for (int _AsmIndex = 0; _AsmIndex < assemblies.Length; _AsmIndex++)
                {
                    if (_Filters.Length > 0)
                    {
                        for (int _FilterIndex = 0; _FilterIndex < _Filters.Length; _FilterIndex++)
                        {
                            _IsValid = !_Filters[_FilterIndex](assemblies[_AsmIndex]);
                            if (!_IsValid)
                            {
                                break;
                            }
                        }
                        if (!_IsValid)
                        {
                            continue;
                        }
                    }
                    //FindTypes(
                    //    new TypeFoundHandler(
                    //        delegate(Type[] type, object state)
                    //        {
                    //            List<Type> _ListState = state as List<Type>;
                    //            _ListState.AddRange(type);
                    //            return true;
                    //        }
                    //    ),
                    //    assemblies[_AsmIndex],
                    //    _Types
                    //);
                }
                return _Types;
            }
            catch
            {
                throw;
            }
        }



        #endregion Methods

        #region Properties
        /// <summary>
        /// Gets the criteria.
        /// </summary>
        /// <value>The criteria.</value>
        public TypeSearchCriteria Criteria
        {
            get
            {
                return _SearchCriteria;
            }
        }


        #endregion Properties



    }
}
